// 兼容性问题 子类型可以赋予给父类型。结构上来看是否兼容
// ts中  结构化的类型系统 (鸭子类型检查：长得像就行). 比如说如果两个类型名字不一样但是无法区分
type a = number
type b = number

let obj :{
    toString():string
}
let str:string = 'avd'
// 这两个类型但从 类型层级来看 是不存在父子关系的

obj= str //兼容性   你要的我有：  我们可以把string 看成一个对象  基于toString扩展了其他的功能

obj.toString()//安全 保证使用的时候不会发生异常

// 接口类型
interface IAnimal{
    name:string,
    age:number
}
interface IPerson{
    name:string,
    age:number,
    address:string
}
let animal:IAnimal
let person:IPerson={
    name:'js',
    age:8,
    address:''
}
animal = person

// 子父关系 不要考虑 谁多谁少  考虑的是父子类型的层级关系  要从安全思考

// 函数的兼容性
let sum1 = (a:string,b:string)=>a+b
let sum2 = (a:string)=>a
sum1 = sum2

let sum3:()=>string|number
let sum4:()=>string

class A{
    private name!:string
    age!:number
}
class B{
    private name!:string
    age!:number
}
let a:A = new B()

// 类型分为两种   结构化类型  标称类型
class Addtype<S>{
    private _type!:S
}
type NewType<T,S extends string> = T & Addtype<S> 
type BTC = NewType<number,'btc'>
type USDT = NewType<number,'usdt'>
let btc=100 as BTC
let usdt =100 as  USDT

function getCount(count:BTC){
    return count
}
getCount(usdt) //标称类型

interface AA{
    name:string
}
interface BB{
    age:number
}

// 逆变和协变   逆变：子->父   协变：商量一下 父->子  (传父、返子)   参数：逆变 返回值：协变
class Parent{
    house(){}
}
class Child extends Parent{
    car(){}
}
class Grandson extends Child{
    sleep(){}
}
// 都是可以通过父子关系来证明  兼容性的
function fn(callback:(instance:Child)=>Child){
    let r = callback(new Grandson()) //你要的我都有
    // r是child的类型 如果用户返回了newGrandson grandson是属于child的子类性的
    // 返回值可以传递子类
    // r.sleep
}
// 1)赋予值的时候可以赋予  自己和子类型
// 2)用户在调用callback的时候 可以传递child或者Grandson（传递了grandson 但是在使用grandson中的属性肯定使用不了了）
// 3）如果用户会回调中，使用属性的时候，要保证范围不能超过Child控制的范围，所以表示grandson的话可能会不安全，但是标示parent 是安全的，因为子类中的属性包含了parent


// 一个值随着输入的变化而变化  协变
// 相反就是逆变

// 参数可以传父亲，返回值可以返回儿子
fn((instance:Parent):Grandson=>{
    return new Grandson
})

type Arg<T> = (arg:T) =>void
type Return<T> = (arg:any) =>T
type isAry = Arg<Parent> extends Arg<Child> ? true :false //逆变
type isReturn = Return<Grandson> extends Return<Child> ? true :false //协变



// 逆变带来的问题
interface Array<T>{
    // concat:(...args:T[])=>T[],//强制触发逆变问题  ---校验是否能逆变
    concat(...args:T[]):T[], //这种写法会禁用逆变的效果，不去检测逆变问题
    [key:number]:any
}
let parentArr:Array<Parent>
let childArr!: Array<Child>
let grandsonArr!:Array<Grandson>
parentArr = childArr

// 泛型的兼容性 泛型比较的是最终的结果 比较的不是泛型传递的参数

interface II<T>{
    a:T
}
let a1!:II<string>
let a2!:II<number>

// type xx = II<string> extends II<number> ? true : false
a1=a2

// 枚举永远不兼容 不能将枚举赋予给另一个枚举
const enum E1{
    a =1
}
const enum E2{
    a=1
}
let a3!:E1
let a4!:E2
a3 = a4



// 传父返子
function fn1(callback:(a:string|number)=>string|boolean){
    callback('string')
    callback(123)
}
fn1((a:boolean|string|number)=>{
    return 'ad'
})
export{}